# Copyright (c) 2022 Robert Bosch GmbH and Microsoft Corporation
#
# This program and the accompanying materials are made available under the
# terms of the Apache License, Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0.
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# SPDX-License-Identifier: Apache-2.0

import asyncio
import logging
import signal
import json

from sdv.util.log import (  # type: ignore
    get_opentelemetry_log_factory,
    get_opentelemetry_log_format,
)
# from sdv.vdb.reply import DataPointReply
from sdv.vehicle_app import VehicleApp, subscribe_topic
from vehicle import Vehicle, vehicle  # type: ignore

# Configure the VehicleApp logger with the necessary log config and level.
logging.setLogRecordFactory(get_opentelemetry_log_factory())
logging.basicConfig(format=get_opentelemetry_log_format())
logging.getLogger().setLevel("DEBUG")
logger = logging.getLogger(__name__)


SET_ATMOSPHERE_LIGHT_REQUEST_TOPIC = "stellantis/setAtmosphereLight"
SET_SEAT_POSITION_REQUEST_TOPIC = "stellantis/setSeatPosition"


class StelantisApp(VehicleApp):

    def __init__(self, vehicle_client: Vehicle):

        super().__init__()
        self.Vehicle = vehicle_client
        self._idx = 0

    async def on_start(self):
        pass

    def convert_color_to_hex(self, color):
        length = len(color)
        ret = []
        while length:
            tmp = color[:2]
            ret.append(int(tmp, 16))
            color = color[2:]
            length = len(color)

        return ret
    
    def is_numeric(self, number, min_value, max_value):
        if type(number).__name__ != 'int':
            logger.info("%s is not of integer type" % number)
            return False
        if number < min_value or number > max_value:
            logger.info("%s value is out of index" % number)
            return False
        return True

    @subscribe_topic(SET_ATMOSPHERE_LIGHT_REQUEST_TOPIC)
    async def set_atmosphere_light_request(self, data_str: str) -> None:

        data = json.loads(data_str)

        action = data["action"]

        light = int(action) << 24

        action_judge = self.is_numeric(action, 1, 8)
        if not action_judge:
            return None

        if action == 1:
            logger.info("action is 1")
            color_str = data.get("color", "#ffffff")
            logger.info("color is %s" % color_str)
            color = color_str[1:]
            rgb = self.convert_color_to_hex(color)
            light |= rgb[0] << 16
            light |= rgb[1] << 8
            light |= rgb[2]

        elif action == 2:
            logger.info("action is 2")
            times = data.get('times', 0)
            logger.info("times %s" % times) 
            times_judge = self.is_numeric(times, 0, 255)
            if not times_judge:
                return None
            speed = data.get('speed', 0x02)
            logger.info("speed %s" % speed)
            speed_judge = self.is_numeric(speed, 2, 10)
            if not speed_judge:
                return None
            color = data.get("color", 1)
            color_judge = self.is_numeric(color, 1, 7)
            if not color_judge:
                return None
            logger.info("color is %s" % color)
            logger.info("current light %s" % light)
            light |= int(color) << 16
            logger.info("add color light is %s" % light)
            light |= speed << 8
            logger.info("add speed light is %s" % light)
            light |= times
            logger.info("add times light is %s" % light)
            logger.info("action 2 light res %s" % light)

        elif action == 3:
            logger.info("action is 3")
            times = data.get('times', 0)
            times_judge = self.is_numeric(times, 0, 255)
            if not times_judge:
                return None
            interval = data.get('interval', 0)
            interval_judge = self.is_numeric(interval, 0, 255)
            if not interval_judge:
                return None
            logger.info("times %s" % times)
            logger.info("interval %s" % interval)
            color = data.get("color", 1)
            color_judge = self.is_numeric(color, 1, 7)
            if not color_judge:
                return None
            light |= int(color) << 16
            light |= interval << 8
            light |= times
            logger.info("action 3 light res %s" % light)

        logger.debug(f'res light: {hex(light)}')

        if light:
            await self.Vehicle.Cabin.Lights.AtmosphereLight.set(light)

    @subscribe_topic(SET_SEAT_POSITION_REQUEST_TOPIC)
    async def set_set_position_request(self, data_str: str) -> None:
        data = json.loads(data_str)
        position = data["position"]
        position_judge = self.is_numeric(position, 1, 9)
        if not position_judge:
            return None
        if position > 0 and position <= 9:

            value = position << 12
            if position == 7:
                interval = data.get('interval', 0x5)
                interval_judge = self.is_numeric(interval, 3, 10)
                if not interval_judge:
                    return None
                times = data.get('times', 0)
                times_judge = self.is_numeric(times, 0, 255)
                if not times_judge:
                    return None
                value |= interval << 8
                value |= times

            logger.debug(f'seat position value: {hex(value)}')
            await self.Vehicle.Cabin.Seat.Row1.Pos1.Position.set(value)


async def main():
    """Main function"""
    logger.info("Starting Stelantis App...")
    # Constructing Stelantis App and running it.
    vehicle_app = StelantisApp(vehicle)
    await vehicle_app.run()

LOOP = asyncio.get_event_loop()
LOOP.add_signal_handler(signal.SIGTERM, LOOP.stop)
LOOP.run_until_complete(main())
LOOP.close()
